import numpy as np
import random

class Individual:

    def __init__(self, config):
        
        self.config = config
        self.x = np.random.randint(low=-1, high=2, size=self.config['DsDim'])
        self.fitness = self.config['evaluationer'].testeval(self.x)

    def update(self, solution1, solution2):

        ## cross
        self.cross_x = np.zeros_like(self.x)
        for index in range(len(solution1)):
            r = random.random()
            if r < self.config['cross_rate']:
                self.cross_x[index] = solution1[index]
            else:
                self.cross_x[index] = solution2[index]
        ## mutation
        for index in range(len(self.cross_x)):
            r = random.random()
            if r < self.config['mutation_rate']:
                temp = np.random.randint(low=-1, high=2)
                while temp == self.cross_x[index]:
                    temp = np.random.randint(low=-1, high=2)
                self.cross_x[index] = temp
        self.x = self.cross_x
        self.fitness = self.config['evaluationer'].testeval(self.x)

class GA:

    def __init__(self, config):

        self.config = config
        self.NP = 2 * self.config['NP']
        self.population = [Individual(self.config) for i in range(self.NP)]
        
    def update(self, ):

        self.solutions = np.zeros((self.NP, 2, self.config['DsDim']))

        count = 0
        while count < 2 * self.NP:

            lister = np.random.permutation(self.NP)
            for index in range(0, self.NP, 2):
                left = lister[index]
                right = lister[index + 1]
                if self.population[left].fitness < self.population[right].fitness:
                    self.solutions[count / 2, count % 2] = self.population[left].x
                else:
                    self.solutions[count / 2, count % 2] = self.population[right].x
                count += 1
        
        for index in range(self.NP):

            self.population[index].update(self.solutions[index, 0], self.solutions[index, 1])
        
    def show(self, ):

        for individual in self.population:
            print(individual.fitness)